﻿using System;
using Uniloader.Managers;
using System.IO;
using System.Security.Cryptography;
using System.Net;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Collections;
using XamlTorrent.Managers.UriGetter.Downloaders;

namespace XamlTorrent.Managers.UriGetter
{
    public class UriDownloadTask : TransferTask
    {
        public UriDownloadTask(Uri source, FileInfo saveAs) : this(source, saveAs, null, null) { }

        public UriDownloadTask(Uri source, FileInfo saveAs, byte[] hashSum, string hashAlgorithmName)
            : base()
        {
            if (source == null)
                throw new ArgumentNullException("source");

            if (saveAs == null)
                throw new ArgumentNullException("saveAs");

            downloadSource = source;
            fileInfo = saveAs;
            fileName = saveAs.Name;
            
            if(hashSum != null)
                checkSum = (byte[])hashSum.Clone();
            checkSumAlg = hashAlgorithmName;
            
            taskState = TaskState.Stopped;

            //WebRequest testReq = WebRequest.Create(source);

            //if (testReq is HttpWebRequest)
            //    downloader = new HttpDownloader(source, saveAs);
            //else if (testReq is FtpWebRequest)
            //    downloader = new FtpDownloader(source, saveAs);
            //else
                downloader = new DefaultDownloader(source, saveAs);

            downloader.MaxSegmentCount = 2;
        }

        /// <summary>
        /// Protocol-aware download agent.
        /// </summary>
        private DownloaderBase downloader;

        #region Start/Stop/Suspend
        public override void Start()
        {
            switch (taskState)
            {
                case TaskState.Paused:
                    throw new NotImplementedException();

                case TaskState.Stopped:
                    downloader.StartDownloadAsync();
                    taskState = TaskState.Transferring;
                    break;
            }
        }

        public override void Stop()
        {
            taskState = TaskState.Stopped;
        }

        public override void Suspend()
        {
        }

        #endregion

        #region Cryptographic Checksum
        private string checkSumAlg;
        public string CheckSumAlgorithm
        {
            get { return checkSumAlg; }
        }

        private byte[] checkSum;
        public byte[] Checksum
        {
            get { return checkSum; }
        }

        public byte[] ComputeCheckSum()
        {
            if (checkSum == null || checkSumAlg == null)
                throw new InvalidOperationException("Checksum information is not available.");

            using (Stream fileData = fileInfo.OpenRead())
            {
                HashAlgorithm hashAlg = HashAlgorithm.Create(checkSumAlg);

                if (hashAlg == null)
                    throw new InvalidOperationException(
                        String.Format("Unknown hash algorithm '{0}'.", checkSumAlg)
                        );

                return hashAlg.ComputeHash(fileData);
            }
        }

        public bool TestCheckSum()
        {
            byte[] hashSum = ComputeCheckSum();

            if (checkSum.Length != hashSum.Length)
                return false; // different hash sum lengths

            for (int i = 0; i < hashSum.Length; i++)
            {
                if (checkSum[i] != hashSum[i])
                    return false;
            }

            return true; // it passed!
        }
        #endregion

        #region Properties
        private TaskState taskState;
        public override TaskState TaskState
        {
            get { return taskState; }
        }

        private Uri downloadSource;
        public override object TransmisionMetadata
        {
            get { return downloadSource; }
        }

        string fileName;
        public override string DisplayName
        {
            get { return fileName; }
        }

        private FileInfo fileInfo;
        public override FileSystemInfo LocalData
        {
            get { return fileInfo; }
        }

        public override TimeSpan RemainingTime
        {
            get { return TimeSpan.MaxValue; }
        }

        public override long BytesSendTarget
        {
            get { return 0; }
        }

        public override long BytesReceiveTarget
        {
            get { return downloader.BytesTotal; }
        }

        public override long BytesSent
        {
            get { return 0; }
        }

        public override long BytesReceived
        {
            get { return downloader.BytesDownloaded; }
        }

        public override double Progress
        {
            get { return ((double)BytesReceived / (double)BytesReceiveTarget); }
        }
        #endregion
    }
}
